<?php
// +----------------------------------------------------------------------
// | XmlDb
// +----------------------------------------------------------------------
// | Author: alex <gt199899@gmail.com>
// +----------------------------------------------------------------------
// | Version: 2014-06-28
// +----------------------------------------------------------------------
// | Copyright: Perfect Is Shit
// +----------------------------------------------------------------------
namespace Lib\XmlDb;
/**
 * @example xml template
 * <table>
 *	<field>
 *		<id>sys</id>
 *		<isdel>sys</isdel>
 *		<datetime>sys</datetime>
 *	</field>
 *	<data>
 *	</data>
 * </table>
 * 
 * @example create
 * $xmlDb = new \Lib\XmlDb\XmlDb(C('PHY_PATH.XMLDB'));
 * $xmlDb->table('test')
 * 		 ->field(array('f1'))
 * 		 ->create();
 * 
 */
class XmlDb{
	
	private $xmlTem = <<<XML
<table>
	<field>
		<id>sys</id>
		<isdel>sys</isdel>
		<datetime>sys</datetime>
	</field>
	<data></data>
</table>
XML;
	
	public $xmlDbPath = '';
	
	private $tableName = '';
	
	private $field = array();
	
	private $where = array();
	
	private $order = array();
	
	static public $xmlDoom;
	
	/**
	 * construct
	 * @author alex<gt199899@gmail.com>
	 * @version 2014-06-28
	 * @copyright Perfect Is Shit
	 */
	public function __construct($xmlDbPath){
		is_dir($xmlDbPath) or trigger_error('xmlDbPath is not a dir', E_USER_ERROR);
		$this->xmlDbPath = $xmlDbPath;
	}
	
	/**
	 * object to array
	 * @param object $obj
	 * @return array $obj
	 * @author www
	 * @version 2014-06-28
	 * @copyright Free
	 */
	public function objToArr($obj){
		if(is_object($obj)){
			$obj = (array)$obj;
			$obj = $this->objToArr($obj);
		} elseif(is_array($obj)){
			foreach($obj as $key => $value){
				$obj[$key] = $this->objToArr($value);
			}
		}
		return $obj;
	}
	
	/**
	 * array to object
	 * @param object $arr
	 * @return array $arr
	 * @author www
	 * @version 2014-06-28
	 * @copyright Free
	 */
	public function arrToObj($arr){
		if(is_array($arr)){
			$arr = (object)$arr;
			$arr = $this->arrToObj($arr);
		}
		else if(is_object($arr)){
			foreach($arr as $key => $value){
				$arr->$key = $this->arrToObj($value);
			}
		}
		return $arr;
	}
	
	/**
	 * table
	 * register static variables $xmlDoom
	 * @author alex<gt199899@gmail.com>
	 * @version 2014-06-28
	 * @copyright Perfect Is Shit
	 */
	public function table($name){
		is_string($name) or trigger_error('table name must be string', E_USER_ERROR);
		$this->tableName = $name;
		$xml_content = $this->tableExists($name) ? file_get_contents($this->getXmlFile($name)) : $this->xmlTem;
		self::$xmlDoom = new \SimpleXMLElement($xml_content);
		return $this;
	}
	
	/**
	 * check table exists
	 * @access public
	 * @param string $name--table name
	 * @return true--table exists
	 * @return false--table not exists
	 * @author alex<gt199899@gmail.com>
	 * @version 2014-07-02
	 * @copyright Perfect Is Shit
	 */
	public function tableExists(){
		is_string($this->tableName) or trigger_error('table name must be string', E_USER_ERROR);
		if(file_exists($this->getXmlFile($this->tableName))){
			return true;
		}
		else{
			return false;
		}
	}
	
	/**
	 * check table must be exists
	 * @access private
	 * @param string $name--table name
	 * @return trigger_error--table is not exists
	 * @return null--table is exists
	 * @author alex<gt199899@gmail.com>
	 * @version 2014-07-02
	 * @copyright Perfect Is Shit
	 */
	private function tableBeExists(){
		$this->tableExists($this->tableName) or trigger_error('table is not exists', E_USER_ERROR);
	}
	
	/**
	 * check table must not be exists
	 * @access private
	 * @param string $name--table name
	 * @return trigger_error--table is exists
	 * @return null--table is not exists
	 * @author alex<gt199899@gmail.com>
	 * @version 2014-07-02
	 * @copyright Perfect Is Shit
	 */
	private function tableBeNotExists(){
		$this->tableExists($this->tableName) and trigger_error('table have been exists', E_USER_ERROR);
	}
	
	/**
	 * get xml file from table name
	 * @access private
	 * @param $name string
	 * @return trigger_error--table is not exists
	 * @return xml file phy address
	 * @author alex<gt199899@gmail.com>
	 * @version 2014-07-02
	 * @copyright Perfect Is Shit
	 */
	private function getXmlFile(){
		return $this->xmlDbPath.'/'.$this->tableName.'.xml';
	}
	
	/**
	 * create table
	 * @access public
	 * @return true|false
	 * @author alex<gt199899@gmail.com>
	 * @version 2014-06-28
	 * @copyright Perfect Is Shit
	 */
	public function create(){
		$this->tableBeNotExists($this->tableName);
		foreach($this->field as $key=>$value){
			self::$xmlDoom->field->addChild($value, $value);
		}
		unset($key, $value);
 		return self::$xmlDoom->asXML($this->getXmlFile($this->tableName));
	}
	
	/**
	 * check field
	 * @access private
	 * @author alex<gt199899@gmail.com>
	 * @version 2014-07-01
	 * @copyright Perfect Is Shit
	 */
	private function checkField($data){
		if(!is_array($data) || empty($data)){
			return false;
		}
		$result = true;
		foreach($data as $key=>$value){
			if(!is_string($value)){
				$result = false;
				break;
			}
		}
		unset($key, $value);
		return $result;
	}
	
	/**
	 * field
	 * @access public
	 * @param $data array
	 * @return $this
	 * @author alex<gt199899@gmail.com>
	 * @version 2014-07-01
	 * @copyright Perfect Is Shit
	 */
	public function field($data){
		$this->checkField($data) or trigger_error('field param must be array',E_USER_ERROR);
		!empty($this->tableName) or trigger_error('did not set table', E_USER_ERROR);
		$this->field = $data;
		return $this;
	}
	
	/**
	 * where
	 * @access public
	 * @param $data array
	 * @return $this
	 * @author alex<gt199899@gmail.com>
	 * @version 2014-07-01
	 * @copyright Perfect Is Shit
	 */
	public function where($data){
		!empty($this->tableName) or trigger_error('did not set table', E_USER_ERROR);
		$this->where = $data;
		return $this;
	}
	
	/**
	 * order
	 * @access public
	 * @param string $key => order by field key
	 * @param string $type => asc,desc
	 * @return $this
	 * @author alex<gt199899@gmail.com>
	 * @version 2014-07-01
	 * @copyright Perfect Is Shit
	 */
	public function order($key, $type="desc"){
		!empty($this->tableName) or trigger_error('did not set table', E_USER_ERROR);
		$this->order = array($key, strtolower($type));
		return $this;
	}
	
	/**
	 * get fields of table
	 * @access public
	 * @param $name string
	 * @return $fields object
	 * @author alex<gt199899@gmail.com>
	 * @version 2014-07-02
	 * @copyright Perfect Is Shit
	 */
	public function getFields(){
		$this->tableBeExists($this->tableName);
		$fields = self::$xmlDoom->field;
		$fields = get_object_vars($fields);
		return $fields;
	}
	
	/**
	 * get size of data
	 * @access public
	 * @return int $size_of_data
	 * @author alex<gt199899@gmail.com>
	 * @version 2014-07-02
	 * @copyright Perfect Is Shit
	 */
	public function getSizeOfData(){
		$this->tableBeExists($this->tableName);
		$data = self::$xmlDoom->data;
		$size_of_data = sizeof(get_object_vars($data));
		return (int)$size_of_data;
	}
	
	/**
	 * get next id
	 * @access public
	 * @return int $next_id
	 * @author alex<gt199899@gmail.com>
	 * @version 2014-07-02
	 * @copyright Perfect Is Shit
	 */
	public function getNextId(){
		$now_id = $this->getSizeOfData();
		$next_id = $now_id + 1;
		return (int)$next_id;
	}
	
	/**
	 * add
	 * 增加list条目
	 * 根据表的field添加
	 * $data里面必须拥有field里面非sys的所有字段否则会添加字段的默认值
	 * @access public
	 * @param $data array
	 * @example in array('f1'=>1,'f2'=>2) out true
	 * @return true => add success
	 * @return fals => add fail
	 * @author alex<gt199899@gmail.com>
	 * @version 2014-07-02
	 * @copyright Perfect Is Shit
	 */
	public function add($data){
		$this->tableBeExists($this->tableName);
		is_array($data) and !empty($data) or trigger_error('params can not be empty and must be array', E_USER_ERROR);
		$fields = $this->getFields($this->tableName);
		$next_id = $this->getNextId();
		$xml_data = self::$xmlDoom->data;
		$xml_data->addchild('list');
		$xml_data = $xml_data->children();
		$xml_data = $xml_data->list[sizeof($xml_data) - 1];
		foreach($fields as $key=>$value){
			$val = isset($data[$key]) ? $data[$key] : $value;
			switch ($key){
				case 'id':
					$val = $next_id;
					break;
				case 'datetime':
					$val = date('Y-m-d H:i:s');
					break;
				case 'isdel':
					$val = 0;
					break;
				default:
					break;
			}   
			$xml_data->addchild($key, (string)$val);
		}
		unset($key, $value);
		return self::$xmlDoom->asXML($this->getXmlFile());
	}
	
	/**
	 * select
	 * @access public
	 * @param $data array
	 * @example in array('f1'=>1,'f2'=>2) out true
	 * @return true => add success
	 * @return fals => add fail
	 * @author alex<gt199899@gmail.com>
	 * @version 2014-07-02
	 * @copyright Perfect Is Shit
	 */
	public function select(){
		$this->tableBeExists($this->tableName);
		$xml_data = self::$xmlDoom->data->children();
		$xml_data = $this->objToArr($xml_data);
		$xml_data = $xml_data['list'];
		$select_data = array();
		if(empty($this->where)){
			$select_data = $xml_data;
		}
		else{
			$selected = false;
			foreach($xml_data as $key=>$value){
				$selected = false;
				foreach($this->where as $k=>$v){
					if(isset($value[$k]) && $value[$k] == $v){
						$selected = true;
						continue;
					}
					else{
						$selected = false;
						break;
					}
				}
				if($selected === true){
					$select_data[] = $value;
				}
			}
		}
		if(empty($this->order)){
			$select_data = $this->arraySort($select_data, 'id', 'desc');
		}
		else{
			$select_data = $this->arraySort($select_data, $this->order[1], $this->order[2]);
		}
		unset($key, $value, $k, $v);
		$this->freeResourse();
		return $select_data;
	}
	
	/**
	 * 二维数组排序
	 * 根据二维数组里面的某个键排序
	 * @param array $arr
	 * @param string $keys
	 * @param string $type
	 * @return array $new_array
	 * @author www
	 * @copyright free
	 */
	public function arraySort($arr,$keys,$type='asc'){
		$keysvalue = $new_array = array();
		foreach ($arr as $k=>$v){
			$keysvalue[$k] = $v[$keys];
		}
		if($type == 'asc'){
			asort($keysvalue);
		}else{
			arsort($keysvalue);
		}
		reset($keysvalue);
		foreach ($keysvalue as $k=>$v){
			$new_array[$k] = $arr[$k];
		}
		return $new_array;
	}
	
	/**
	 * unset params
	 */
	public function freeResourse(){
		$this->tableName = '';
		$this->order = array();
		$this->field = array();
		$this->where = array();
	}
	
}